require "rubygems"
require "activerecord"


namespace :brokencompass do

  desc "Creates indexes"
  task :index do
    brokencompass_logger ||= Logger.new("#{RAILS_ROOT}/log/brokencompass.log")
    brokencompass_logger.info("Starting index creation at #{Time.now}")

    if File.exist?(File.join(RAILS_ROOT,"config","brokencompass.yml"))
      brokencompass_config = YAML::load(File.open(File.join(RAILS_ROOT,"config","brokencompass.yml")))
        # Words to exclude from search
        words_to_exclude = ["to", "from", "the", "at", "in", "and", "of","or","for"]

        # Flag to check indexer for case-sensitivity
        case_sensetive = false

      # Creating Generic model
      class GenericModel < ActiveRecord::Base
      end

      #Connecting using adapter from config
      GenericModel.establish_connection(brokencompass_config["connection_adapter"])

      #For every index-sources, generate the indexes
      all_indexsources = brokencompass_config["index-sources"]
      all_indexsources ||= {}
      all_indexsources.each do |isrc_key,isrc_value|
        t1 = Time.now
        brokencompass_logger.info("Creating index for #{isrc_key.inspect}")

        #Sets the sql to be used to query data(from database) for making index
        index_sql = isrc_value["sql"]
        index_sql ||= "select * from #{isrc_key.to_s.pluralize}"
        brokencompass_logger.info("          Using sql: #{index_sql}")

        #Sets the table name to GeneralModel
        table_name = isrc_value["table_name"]
        table_name ||= isrc_key.to_s.pluralize
        GenericModel.set_table_name(table_name)

        # Hash to store indexing
        indexing_hash  = Hash.new

        # Fetching all data
        complete_resultset = GenericModel.find_by_sql(index_sql)

        complete_resultset.each do |single_result|
          # Attributes to index
          searchable_attributes = single_result.attribute_names

          if searchable_attributes.include?(GenericModel.primary_key)
            (searchable_attributes - [GenericModel.primary_key]).each do |attribute|
                indexing_hash[attribute] = Hash.new if indexing_hash[attribute].nil?
                attribute_content = single_result.send(attribute)

                #todo: Splits the word using a single space, modify it to split on more generic pattern
                split_pattern = /[^a-zA-Z0-9-]/
                splitted_attribute_content = attribute_content.to_s.split(split_pattern).compact.collect{|x| x.strip.blank? ? nil : x.strip }.compact

                #excluding words from blacklist
                splitted_attribute_content = splitted_attribute_content.collect {|x| words_to_exclude.include?(x.downcase) ? nil : x}.compact
                splitted_attribute_content.each do |splitted_word|
                  #reacting to case-sensetivity flag
                  splitted_word = splitted_word.downcase unless case_sensetive
                  indexing_hash[attribute][splitted_word] = Array.new if indexing_hash[attribute][splitted_word].nil?
                  indexing_hash[attribute][splitted_word] << single_result.id
                end
              end
          else
            brokencompass_logger.info("Error: primary key not available in query.")
          end

        end

        brokencompass_logger.info("          Writing index file..")
        File.open(File.join(RAILS_ROOT,"broken_compass","#{isrc_key}.index"), 'w+') do |f|
          Marshal.dump(indexing_hash, f)
        end
        t2 = Time.now
        brokencompass_logger.info("          Completes in #{(t2.to_f - t1.to_f)} seconds")

      end
    else
      brokencompass_logger.info("Not able to access '#{File.join("config","brokencompass.yml")}'")
    end
  end

  desc "Creates broken_compass directory"
  task :addfolder do
    unless File.exist?(File.join(RAILS_ROOT,"broken_compass"))
      Dir.mkdir(File.join(RAILS_ROOT,"broken_compass"))
    end
  end

  desc "Creates indexes from scratch"
  task :create_index => [:addfolder, :index]

end
